home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / CACHE.ASM < prev    next >
Assembly Source File  |  1986-06-04  |  15KB  |  255 lines

  1. INTERRUPTS      SEGMENT AT 0H    ;This is where the disk interrupt
  2.         ORG     13H*4            ;holds the address of its service routine
  3. DISK_INT        LABEL   DWORD
  4. INTERRUPTS      ENDS
  5.  
  6. CODE_SEG        SEGMENT
  7.         ASSUME  CS:CODE_SEG
  8.         ORG     100H            ;ORG = 100H to make this into a .COM file
  9. FIRST:  JMP     LOAD_CACHE      ;First time through jump to initialize routine
  10.  
  11.         CPY_RGT DB      '(C)1985 S.Holzner'     ;A signature in bytes
  12.         TBL_LEN DW      64 ;<-- # OF SECTORS TO STORE IN CACHE, MIN=24, MAX=124.
  13.   ;THIS IS THE ONLY PLACE YOU MUST SET THIS NUMBER. EACH SECTOR = 512 BYTES.
  14.         TIME    DW      0       ;Time used to time-stamp each sector
  15.         OLD_CX  DW      0       ;Stores original value of CX (CX is used often)
  16.         LOW_TIM DW      0       ;Used in searching for least recently used sect.
  17.         INT13H  DD      0       ;Stores the original INT 13H address
  18.         RET_ADR LABEL   DWORD   ;Playing games with the stack here to preserve
  19.         RET_ADR_WORD    DW      2 DUP(0)            ;flags returned by Int 13H
  20.  
  21. DISK_CACHE      PROC    FAR     ;The Disk interrupt will now come here.
  22.         ASSUME  CS:CODE_SEG
  23.         CMP     AX,201H         ;Is this a read (AH=2) of 1 sector (AL=1)?
  24.         JE      READ            ;Yes, jump to Read
  25.         CMP     AH,3            ;No. Perchance a write or format?
  26.         JB      OLD_INT         ;No, release control to old disk Int.
  27.         JMP     WRITE           ;Yes, jump to Write
  28. OLD_INT:PUSHF                   ;Pushf for Int 13H's final Iret
  29.         CALL    INT13H          ;Call the Disk Int
  30.         JMP     PAST            ;And jump past all usual Pops
  31. READ:   PUSH    BX              ;Push just about every register ever heard of
  32.         PUSH    CX
  33.         PUSH    DX
  34.         PUSH    DI
  35.         PUSH    SI
  36.         PUSH    DS
  37.         PUSH    ES
  38.         MOV     DI,BX       ;Int 13H gets data address as ES:BX, switch to ES:DI
  39.         ASSUME  DS:CODE_SEG     ;Make sure all labels found correctly
  40.         PUSH    CS              ;Move CS into DS by pushing CS, popping DS
  41.         POP     DS
  42.         MOV     OLD_CX,CX       ;Save original CX since we're about to use it
  43.         CMP     DH,0            ;DH holds requested head -- head 0?
  44.         JNE     NOT_FAT1        ;Nope, this can't be the first Fat sector
  45.         CMP     CX,6            ;If this is the directory, check if we have a
  46.         JE      FAT1            ; new disk.
  47.         CMP     CX,2            ;Track 0 (CH)? Sector 2 (CL)?
  48.         JNE     NOT_FAT1        ;If not, this sure isn't the FAT1
  49. FAT1:   CALL    FIND_MATCH  ;DOS reads in this sector first to check disk format
  50.         JCXZ    NONE            ;We'll use it for a check-sum. Do we have it
  51.         MOV     BX,DI           ; stored yet? CX=0-->no. If yes, restore BX
  52.         MOV     CX,OLD_CX       ; and CX from original values
  53.         PUSHF                   ;And now do the Pushf and call of Int13H to read
  54.         CALL    INT13H          ; FAT1
  55.         JC      ERR             ;If error, leave
  56.         MOV     CX,256          ;No error, FAT1 was read, check our value
  57. REPE    CMPSW                   ; with CMPSW -- if no match, disk was changed
  58.         JCXZ    BYE             ;Everything checks out, Bingo, exit.
  59.         LEA     SI,TABLE        ;New Disk! Zero all the old disk's sectors
  60.         MOV     CX,TBL_LEN      ;Loop over all entries, DL holds drive #
  61. CLR:    CMP     DS:[SI+2],DL    ;Is this stored sector from the old disk?
  62.         JNE     NO_CLR          ;Nope, don't clear this entry
  63.         MOV     WORD PTR DS:[SI],0      ;Match, zero this entry, zero first word
  64. NO_CLR: ADD     SI,518      ;Move on to next stored sector (512 bytes of stored
  65.         LOOP    CLR         ; sector and 3 words of identification & time-stamp)
  66.         JMP     BYE             ;Reset for new disk, let's leave
  67. NONE:   CALL    STORE_SECTOR    ;Store FAT1 if there was no match to it
  68.         JC      ERR             ;Error -- exit ungraciously
  69.         JMP     BYE             ;No Error, Bye.
  70. NOT_FAT1:                       ;The requested sector was not FAT1. Let's
  71.         CALL    FIND_MATCH      ;get it. Or do we have it already?
  72.         JCXZ    NO_MATCH        ;No, jump to No_Match, store sector
  73.         MOV     CX,512          ;ES:DI and DS:SI already set up from Find_Match
  74. REP     MOVSB                   ;Move 512 bytes to requested memory area
  75.         CMP     WORD PTR [BX+4],0FFFFH          ;Is this a a directory sector?
  76.         JE      BYE             ;Yes, don't reset time (already highest poss.)
  77.         INC     TIME            ;No, reset the time, this sector just accessed
  78.         MOV     AX,TIME         ;Move time into Time word of sector's 3 words
  79.         MOV     [BX+4],AX       ; of identification
  80.         JMP     BYE             ;And leave. If there's an article you'd like to
  81. NO_MATCH:                       ;see, by all means write in C/O PC Magazine.
  82.         CALL    STORE_SECTOR    ;Don't have this sector yet, get it.
  83.         JC      ERR             ;If read failed, exit with error
  84. BYE:    CLC                     ;The exit point. Clear carry flag, set AX=1
  85.         MOV     AX,1            ; CY=0 --> no error, AH=0 --> error code = 0
  86. ERR:    POP     ES              ;If error, preserve flags and AX with error code
  87.         POP     DS              ;Pop all conceivable registers (except AX)
  88.         POP     SI
  89.         POP     DI
  90.         POP     DX
  91.         POP     CX              ;Now that the flags are set, we want to get the
  92.         POP     BX              ;old flags off the stack (put there by original
  93. PAST:   POP     CS:RET_ADR_WORD ;Int call) To do that we save the return address
  94.         POP     CS:RET_ADR_WORD[2]      ;first and then pop the flags harmlessly
  95.         POP     CS:OLD_CX       ;into Old_CX, and then jump to RET_ADR.
  96.         JMP     CS:RET_ADR      ;Done with read. Now let's consider write.
  97. WRITE:  PUSH    BX              ;Push all registers, past and present
  98.         PUSH    CX
  99.         PUSH    DX
  100.         PUSH    DI
  101.         PUSH    SI
  102.         PUSH    DS
  103.         PUSH    ES
  104.         PUSH    AX
  105.         CMP     AX,301H         ;Is this a write of one sector?
  106.         JNE     NOSAVE          ;No, don't save it in the sector bank
  107.         PUSH    CS              ;Yep, set DS (for call to Int13H label) and
  108.         POP     DS              ; write this sector out
  109.         PUSHF
  110.         CALL    INT13H
  111.         JNC     SAVE       ;If there was an error we don't want to save sector
  112.         POP     CS:OLD_CX       ;Save AH error code, Pop old AX into Old_CX
  113.         JMP     ERR             ;And jump to an ignoble exit
  114. SAVE:   MOV     OLD_CX,CX       ;We're going to save this sector.
  115.         MOV     DI,BX           ;Set up DI for string move (to store written
  116.         CALL    FIND_MATCH      ; sector. Do we have it in memory? (set SI)
  117.         JCXZ    LEAVE           ;Nope, Leave (like above's Bye).
  118.         XCHG    DI,SI           ;Exchange destination and source
  119.         PUSH    ES              ;Set up DS:SI to point to where data written
  120.         POP     DS              ; from. We'll then use a string move
  121.         PUSH    CS              ;Set up ES so ES:DI points to sector bank
  122.         POP     ES              ; SI was set by Find_Match, Xchg'd into DI
  123.         MOV     CX,512          ;Get ready to move 512 bytes
  124. REP     MOVSB                   ;Here we go
  125. LEAVE:  POP     AX              ;Here is the leave
  126.         JMP     BYE             ;Which only pops AX and then jumps to Bye
  127. NOSAVE: PUSH    CS              ;More than 1 sector written, don't save but
  128.         POP     DS              ; do zero stored sectors that will be written
  129.         MOV     AH,0            ;Use AX as loop index (AL=# of sectors to write)
  130. TOP:    PUSH    CX              ;Save CX since destroyed by Find_Match
  131.         CALL    FIND_MATCH      ;Do we have this one?
  132.         JCXZ    NOPE            ;Nope if CX = 0
  133.         MOV     WORD PTR [BX],0 ;There is a match, zero this sector
  134. NOPE:   POP     CX              ;Restore CX, the sector index
  135.         INC     CL              ;Move on to next one
  136.         DEC     AX              ;Decrement loop index
  137.         JNZ     TOP             ;And, unless that gives 0, go back again
  138. POPS:   POP     AX              ;Pop 'em all, starting with AX
  139.         POP     ES
  140.         POP     DS
  141.         POP     SI
  142.         POP     DI
  143.         POP     DX
  144.         POP     CX
  145.         POP     BX
  146.         JMP     OLD_INT         ;And go back to OLD_INT for write.
  147. DISK_CACHE      ENDP
  148.  
  149. FIND_MATCH      PROC    NEAR    ;This routine finds a sector in the sector bank
  150.         PUSH    AX              ;And returns SI set to sector's entry, BX set
  151.         LEA     SI,SECTORS      ; to the beginning of the 'table' -- the 3 words
  152.         LEA     BX,TABLE        ;that precede all sectors. If there was no match
  153.         MOV     AX,TBL_LEN      ; CX=0. When Int13H called, CH=trk #, CL=sec. #
  154.         XCHG    AX,CX           ; DH=head #, DL=Drive #. Get Tbl_Len into CX
  155. FIND:   CMP     DS:[BX],AX      ;Compare stored sector's original AX to current
  156.         JNE     NO              ;If not, not.
  157.         CMP     DS:[BX+2],DX    ;If so, check DX of stored sector with current
  158.         JE      GOT_IT          ;Yes, there is a match, leave
  159. NO:     ADD     BX,518          ;Point to next Table entry
  160.         ADD     SI,518          ;And next sector too
  161.         LOOP    FIND            ;Keep looping until there is a match
  162. GOT_IT: POP     AX              ;If there is no match, CX will be left 0
  163.         RET                     ;Return
  164. FIND_MATCH      ENDP
  165.  
  166. STORE_SECTOR    PROC    NEAR    ;This routine, as it says, stores sectors
  167.         MOV     BX,DI           ;Original BX (ES:BX was original data address)
  168.         MOV     CX,OLD_CX       ; and CX restored (CX=trk#, Sector#)
  169.         PUSHF                   ;Pushf for Int 13H's Iret and call it
  170.         CALL    INT13H
  171.         JNC     ALL_OK          ;If there was an exit, exit ignominiously
  172.         JMP     FIN             ;If error, leave CY flag set, code in AH, exit
  173. ALL_OK: PUSH    CX              ;No error, push used registers
  174.         PUSH    BX              ; and find space for sector in sector bank
  175.         PUSH    DX
  176.         LEA     DI,SECTORS      ;Point to sector bank
  177.         LEA     BX,TABLE        ; and Table
  178.         MOV     CX,TBL_LEN      ; and get ready to loop over all of them to
  179. CHK0:   CMP     WORD PTR DS:[BX],0      ;find if there is an unused sector
  180.         JE      FOUND           ;If the first word is 0, use this sector
  181.         ADD     DI,518          ;But this one isn't so update DI, SI and
  182.         ADD     BX,518          ; loop again
  183.         LOOP    CHK0
  184.         MOV     LOW_TIM,0FFFEH  ;All sectors were filled, find least recently
  185.         LEA     DI,SECTORS      ; used and write over that one
  186.         LEA     SI,TABLE
  187.         MOV     CX,TBL_LEN      ;Loop over all stored sectors
  188. CHKTIM: MOV     DX,LOW_TIM      ;Compare stored sector to so-far low time
  189.         CMP     [SI+4],DX
  190.         JA      MORE_RECENT     ;If this one is more recent, don't use it
  191.         MOV     AX,DI           ;This one is older than previous oldest
  192.         MOV     BX,SI           ;Store sector bank address (DI) and table
  193.         MOV     DX,[SI+4]       ; entry (now in SI)
  194.         MOV     LOW_TIM,DX      ;And update the Low Time to this one
  195. MORE_RECENT:
  196.         ADD     DI,518          ;Move on to next stored sector
  197.         ADD     SI,518          ;And next table entry
  198.         LOOP    CHKTIM          ;Loop again until all covered
  199.         MOV     DI,AX           ;Get Sector bank address of oldest into DI
  200. FOUND:  POP     DX              ;Restore used registers
  201.         POP     SI              ;Old BX (data read-to-address) --> SI
  202.         POP     CX
  203.         MOV     [BX],CX         ;Store the new CX as the sector's first word
  204.         MOV     [BX+2],DX       ;2nd word of Table is sector's DX
  205.         INC     TIME            ;Now find the new time
  206.         MOV     AX,TIME         ;Prepare to move it into 3rd word of Table
  207.         CMP     DH,0            ;Is this directory or FAT? (time-->FFFF)
  208.         JNE     SIDE1           ;If head is not 0, check other head
  209.         CMP     CX,9            ;Head zero, trk# 0, first sector? (directory)
  210.         JLE     DIR             ;Yes, this is a piece we always want stored
  211.         JMP     NOT_DIR         ;No, definitely not FAT or directory
  212. SIDE1:  CMP     DH,1            ;Head 1?
  213.         JNE     NOT_DIR         ;No, this is not File Alloc. Table or directory
  214.         CMP     CX,2            ;Part of the top of the directory?
  215.         JA      NOT_DIR         ;No, go to Not_Dir and set time
  216. DIR:    MOV     AX,0FFFFH       ;Dir or FAT, set time high so always kept
  217. NOT_DIR:MOV     [BX+4],AX       ;Not FAT or dir, store the incremented time
  218.         PUSH    ES              ;And now get the data to fill the sector
  219.         POP     DS              ;SI, DI already set. Now set ES and DS for
  220.         PUSH    CS              ; string move.
  221.         POP     ES
  222.         MOV     CX,512          ;Move 512 bytes
  223. REP     MOVSB                   ;Right here
  224.         CLC                     ;Clear the carry flag (no error)
  225. FIN:    RET                     ;Error exit here (do not reset CY flag)
  226. STORE_SECTOR    ENDP
  227. TABLE:  DW      3 DUP(0)        ;Table and sector storage begins right here
  228. SECTORS:                        ;First thing to write over is the following
  229.                                 ; booster program.
  230. LOAD_CACHE        PROC    NEAR  ;This procedure intializes everything
  231.         LEA     BX,CLEAR
  232.         ASSUME  DS:INTERRUPTS   ;The data segment will be the Interrupt area
  233.         MOV     AX,INTERRUPTS
  234.         MOV     DS,AX
  235.         MOV     AX,word ptr DISK_INT    ;Get the old interrupt service routine
  236.         MOV     word ptr INT13H,AX      ; address and put it into our location         MOV     AX,word ptr DISK_INT[2]
  237.                                         ; INT13H so we can call it.
  238.         MOV     word ptr INT13H[2],AX
  239.         MOV     word ptr DISK_INT,OFFSET DISK_CACHE  ;Now load address of Cache
  240.         MOV     word ptr DISK_INT[2],CS   ;routine into the Disk interrupt
  241.         MOV     AX,TBL_LEN              ;The number of sectors to store in cache
  242.         MOV     CX,518                  ;Multiply by 518 (3 words of id and 512
  243.         MUL     CX                      ; bytes of sector data)
  244.         MOV     CX,AX                   ;Also, zero all the bytes so that
  245. ZERO:   MOV     BYTE PTR CS:[BX],0      ; Store_Sector will find 1st word a 0,
  246.         INC     BX                      ; indicating virgin territory.
  247.         LOOP    ZERO
  248.         MOV     DX,OFFSET TABLE         ;To attach in memory, add # bytes to
  249.         ADD     DX,AX                   ;store to Table's location and use
  250.         INT     27H                     ; Int 27H
  251. LOAD_CACHE        ENDP
  252. CLEAR:
  253.         CODE_SEG        ENDS
  254.         END     FIRST           ;END "FIRST" so 8088 will go to FIRST first.
  255.